﻿using System.Diagnostics;
using Base.FileCollect;
using Base.FileGateway.PdfConvert.Model;
using Base.FileModel.BaseFile;
using Base.FileService.Helper;
using Base.FileService.Interface;
using WeDonekRpc.Client;
using WeDonekRpc.Client.Interface;
using WeDonekRpc.Helper;

namespace Base.FileGateway.PdfConvert
{
    internal class PdfConvertTask
    {
        private readonly long _FileId;

        private readonly FileInfo _File;

        private event Action<PdfResult> _Complate;

        private volatile bool _IsComplete = false;

        private PdfResult _Result;

        public bool IsComplete => this._IsComplete;
        public int EndTime
        {
            get;
            private set;
        }

        public PdfConvertTask ( long fileId, FileInfo file )
        {
            this._File = file;
            this._FileId = fileId;
        }
        public void RegEvent ( Action<PdfResult> ev )
        {
            if ( this._IsComplete )
            {
                ev(this._Result);
                return;
            }
            this._Complate += ev;
        }
        public void Begin ()
        {
            _ = Task.Factory.StartNew(() =>
            {
                try
                {
                    this._Begin();
                }
                catch ( Exception e )
                {
                    ErrorException error = ErrorException.FormatError(e);
                    if ( error.IsSystemError )
                    {
                        error.Save("file");
                    }
                    this._SetError(error.ErrorCode);
                }
            });
        }
        private void _Begin ()
        {
            using ( IScoreService scope = RpcClient.Ioc.CreateTempScore() )
            {
                IUserPdfFileCollect pdfFile = scope.Resolve<IUserPdfFileCollect>();
                long fileId = pdfFile.GetPdfFileId(this._FileId);
                if ( fileId != 0 )
                {
                    this._Success(fileId);
                }
                else if ( this._ConvertPdf(scope, out fileId) )
                {
                    pdfFile.Add(this._FileId, fileId);
                    this._Success(fileId);
                }
            }
        }
        private bool _ConvertPdf ( IScoreService scope, out long fileId )
        {
            IPdfFileConfig config = scope.Resolve<IPdfFileConfig>();
            if ( !File.Exists(config.LibreOfficePath) )
            {
                this._SetError("file.libreoffice.not.find");
                fileId = 0;
                return false;
            }
            IDirService dir = scope.Resolve<IDirService>();
            IDirState state = dir.GetTempDir();
            string path = state.GetFullPath(Path.Combine("PdfConvert", this._File.LastWriteTime.ToString("yyyyMMdd"), Path.GetFileNameWithoutExtension(this._File.Name) + ".pdf"));
            FileInfo pdf = new FileInfo(path);
            if ( pdf.Exists )
            {
                fileId = this._RegFile(scope, dir, pdf);
                return true;
            }
            if ( pdf.Directory.Exists == false )
            {
                pdf.Directory.Create();
            }
            string param = string.Format("--headless --invisible --norestore --convert-to pdf:writer_pdf_Export \"{0}\" --outdir \"{1}\"", this._File.FullName, pdf.Directory.FullName);
            if ( !this._Run(config, param) )
            {
                this._SetError("file.libreoffice.run.fail");
                fileId = 0;
                return false;
            }
            int num = 0;
            do
            {
                pdf.Refresh();
                if ( pdf.Exists )
                {
                    fileId = this._RegFile(scope, dir, pdf);
                    return true;
                }
                num += 1;
                Thread.Sleep(1000);
            } while ( num <= 1 );
            this._SetError("file.pdf.convert.fail");
            fileId = 0;
            return false;
        }
        private void _Success ( long fileId )
        {
            this._Result = new PdfResult
            {
                FileId = fileId,
                IsError = false
            };
            this.EndTime = HeartbeatTimeHelper.HeartbeatTime;
            this._IsComplete = true;
            this._Complate(this._Result);
        }
        private long _RegFile ( IScoreService scope, IDirService dir, FileInfo pdf )
        {
            long fileSize = pdf.Length;
            IDirState state = dir.GetDir(ref fileSize);
            FileDatum datum = state.SaveFile(pdf);
            IFileCollect service = scope.Resolve<IFileCollect>();
            long fileId = service.FindFileId(datum.FileMd5);
            if ( fileId == 0 )
            {
                return service.Add(datum);
            }
            return fileId;
        }
        private bool _Run ( IPdfFileConfig config, string param )
        {
            using ( Process process = new Process() )
            {
                process.StartInfo = new ProcessStartInfo
                {
                    FileName = config.LibreOfficePath,
                    RedirectStandardOutput = false,
                    UseShellExecute = false,
                    Arguments = param,
                    WindowStyle = ProcessWindowStyle.Normal,
                    CreateNoWindow = true,
                    ErrorDialog = false
                };
                if ( process.Start() )
                {
                    process.WaitForExit();
                    return true;
                }
                return false;
            }
        }
        private void _SetError ( string error )
        {
            this._Result = new PdfResult
            {
                IsError = true,
                Error = error
            };
            this.EndTime = HeartbeatTimeHelper.HeartbeatTime;
            this._IsComplete = true;
            this._Complate(this._Result);
        }
    }
}
